// Copyright 2011 Valentin Kasas.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package mime

import (
	"http"
	"mime"
	"strings"
)

// MimeAwareHandler wraps handler into a new http.Handler that will only process
// requests which MIME type is one of mimeTypes.
type MimeAwareHandler struct {
	handler   http.Handler
	mimeTypes []string
}

func (h *MimeAwareHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if h.typeMatches(r) {
		h.handler.ServeHTTP(w, r)
	} else {
		http.NotFound(w, r)
	}
}

// typeMatches tells whether the requested mime type matches
// with one of those supported by h.
func (h *MimeAwareHandler) typeMatches(r *http.Request) bool {
	requestedMime := getMime(r)
	for _, mimeType := range h.mimeTypes {
		if match(requestedMime, mimeType) {
			return true
		}
	}
	return false
}

// getMime extracts the requested mime type of r.
func getMime(r *http.Request) (mimeType string) {
	// first seek an extension in the URL
	ext := seekExtension(r.URL.Path)
    mimeType, _ = mime.ParseMediaType(mime.TypeByExtension(ext))
	if len(mimeType) == 0 {
		// then seek a Content-Type header
		mimeType, _ = mime.ParseMediaType(r.Header.Get("Content-Type"))
	}
	return
}

// seekExtension looks in path for an extension.
// For example, seekExtension("/foo/bar.xml") will
// return ".xml".
// If no extension is present, seekExtension returns an
// empty string.
func seekExtension(path string) (ext string) {
	ind := strings.LastIndex(path, "/")
	if dotInd := strings.LastIndex(path[ind+1:], "."); dotInd != -1 {
		ext = path[ind+1+dotInd:]
	}
	return
}

// match tells whether the provided mime type is compliant
// to the required one.
func match(required, provided string) (ok bool) {
	reqParts := strings.Split(required, "/")
	provParts := strings.Split(provided, "/")
	if len(reqParts) == len(provParts) {
		ok = true
		for i, reqPart := range reqParts {
			ok = ok && (reqPart == "*" || provParts[i] == "*" || reqPart == provParts[i])
		}
	}
	return
}

// TODO : take encoding and other parameters into account while deducing mime type
